package anjiplus.aj_flutter_appsp;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;

import com.anji.appsp.sdk.AppSpConfig;
import com.anji.appsp.sdk.AppSpLog;
import com.anji.appsp.sdk.model.AppSpModel;
import com.anji.appsp.sdk.model.AppSpNoticeModelItem;
import com.anji.appsp.sdk.model.AppSpVersion;
import com.anji.appsp.sdk.notice.service.IAppSpNoticeCallback;
import com.anji.appsp.sdk.version.service.IAppSpVersionCallback;
import com.google.gson.Gson;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/**
 * AjFlutterAppSpPlugin
 */
public class AjFlutterAppspPlugin implements FlutterPlugin, MethodCallHandler {
    private static Registrar registrar;
    private static MethodChannel channel;
    private Context context;
    //为了解决并发问题，比如多次点击，异常情况时候容易出问题
    private ConcurrentLinkedQueue<MethodResultWrapper> wrappers = new ConcurrentLinkedQueue<>();

    // @deprecated Not used by v2.
    public static void registerWith(Registrar registrar) {
        AjFlutterAppspPlugin.registrar = registrar;
        AjFlutterAppspPlugin.channel = new MethodChannel(registrar.messenger(), "aj_flutter_appsp");
        channel.setMethodCallHandler(new AjFlutterAppspPlugin());
    }

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aj_flutter_appsp");
        channel.setMethodCallHandler(this);
        context = flutterPluginBinding.getApplicationContext();
    }

    @Override
    public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) {
        channel.setMethodCallHandler(null);
    }

    // MethodChannel.Result wrapper that responds on the platform thread.
    private static class MethodResultWrapper implements MethodChannel.Result {
        private MethodChannel.Result methodResult;
        private Handler handler;

        MethodResultWrapper(MethodChannel.Result result) {
            methodResult = result;
            handler = new Handler(Looper.getMainLooper());
        }

        @Override
        public void success(final Object result) {
            handler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            methodResult.success(result);
                        }
                    });
        }

        @Override
        public void error(
                final String errorCode, final String errorMessage, final Object errorDetails) {
            AppSpLog.d("Test error  ");
            handler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            methodResult.error(errorCode, errorMessage, errorDetails);
                        }
                    });
        }

        @Override
        public void notImplemented() {
            handler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            methodResult.notImplemented();
                        }
                    });
        }
    }

    /**
     * 初始化
     *
     * @param appKey
     * @param host   如果为空，认为用SDK默认请求地址
     * @param debug  日志开关是否打开，默认打开
     */
    private void init(String appKey, String host, boolean debug) {
        AppSpConfig.getInstance()
                .init(context, appKey)
                //可修改基础请求地址
                .setHost(host)
                //正式环境可以禁止日志输出，通过Tag APP-SP过滤看日志
                .setDebuggable(debug)
                //务必要初始化，否则后面请求会报错
                .deviceInit();
        MethodResultWrapper wrapper = peekWraper();
        if (wrapper != null) {
            wrapper.success("");
        }
    }

    /**
     * 版本更新检查
     */
    private void checkVersion() {
        AppSpConfig.getInstance().getVersion(new IAppSpVersionCallback() {
            @Override
            public void update(AppSpModel<AppSpVersion> spModel) {
                AppSpLog.d("Test updateModel is " + spModel);
                MethodResultWrapper wrapper = peekWraper();
                if (spModel == null) {
                    if (wrapper != null) {
                        wrapper.notImplemented();
                    }
                } else {
                    //先转成json
                    if (spModel.getRepData() != null) {
                        if (wrapper != null) {
                            wrapper.success(new Gson().toJson(spModel));
                        }
                    } else {
                        AppSpModel tempModel = new AppSpModel<>();
                        tempModel.setRepCode(spModel.getRepCode());
                        tempModel.setRepMsg(spModel.getRepMsg());
                        if (wrapper != null) {
                            wrapper.success(new Gson().toJson(tempModel));
                        }
                    }
                }

            }

            @Override
            public void error(String code, String msg) {
                MethodResultWrapper wrapper = peekWraper();
                AppSpModel spModel = new AppSpModel<>();
                spModel.setRepCode(code);
                spModel.setRepMsg(msg);
                if (wrapper != null) {
                    wrapper.success(new Gson().toJson(spModel));
                }
            }
        });
    }

    private void checkNotice() {
        AppSpConfig.getInstance().getNotice(new IAppSpNoticeCallback() {
            @Override
            public void notice(AppSpModel<List<AppSpNoticeModelItem>> noticeModel) {
                AppSpLog.d("Test noticeModel is " + noticeModel);
                MethodResultWrapper wrapper = peekWraper();
                if (noticeModel == null) {
                    if (wrapper != null) {
                        wrapper.notImplemented();
                    }
                } else if (noticeModel.getRepData() != null) {
                    if (wrapper != null) {
                        wrapper.success(new Gson().toJson(noticeModel));
                    }
                } else {
                    //先转成json
                    AppSpModel tempModel = new AppSpModel<>();
                    tempModel.setRepCode(noticeModel.getRepCode());
                    tempModel.setRepMsg(noticeModel.getRepMsg());
                    if (wrapper != null) {
                        wrapper.success(new Gson().toJson(tempModel));
                    }
                }
            }

            @Override
            public void error(String code, String msg) {
                AppSpModel noticeModel = new AppSpModel<>();
                noticeModel.setRepCode(code);
                noticeModel.setRepMsg(msg);
                MethodResultWrapper wrapper = peekWraper();
                if (wrapper != null) {
                    wrapper.success(new Gson().toJson(noticeModel));
                }
            }
        });
    }

    /**
     * 获取当前的result
     *
     * @return
     */
    private MethodResultWrapper peekWraper() {
        if (wrappers == null
                || wrappers.isEmpty()) {
            return null;
        }
        return wrappers.remove();
    }

    /**
     * 只考虑最后一次
     */
    private void removeAllWrapper() {
        if (wrappers == null) {
            return;
        }
        wrappers.clear();
    }

    /**
     * 加入唯一的result
     *
     * @param wrapper
     */
    private void addWraper(MethodResultWrapper wrapper) {
        if (wrappers == null) {
            return;
        }
        wrappers.add(wrapper);
    }

    ApkDownloadTask apkDownloadTask;

    @Override
    public void onMethodCall(MethodCall call, Result result) {
        if (context == null) {
            if (registrar != null) {
                context = registrar.context();
            }
        }
        removeAllWrapper();
        addWraper(new MethodResultWrapper(result));
        //日志开关
        if (call.method.equals("init")) {
            String appKey = null;
            String host = null;
            boolean debug = true;
            Object parameter = call.arguments();
            if (parameter instanceof Map) {
                appKey = (String) ((Map) parameter).get("appKey");
                host = (String) ((Map) parameter).get("host");
                debug = (Boolean) ((Map) parameter).get("debug");
                init(appKey, host, debug);
            }
            //版本请求
        } else if (call.method.equals("getUpdateModel")) {
            checkVersion();
            //公告获取
        } else if (call.method.equals("getNoticeModel")) {
            checkNotice();
            //下载apk并且安装
        } else if (call.method.equals("downloadApkAndInstall")) {
            Object parameter = call.arguments();
            String url = "";
            String path = "";
            if (parameter instanceof Map) {
                url = (String) ((Map) parameter).get("url");
                path = (String) ((Map) parameter).get("path");
            }
            if (TextUtils.isEmpty(url)) {
                MethodResultWrapper wrapper = peekWraper();
                if (wrapper != null) {
                    wrapper.success("UrlFormatError");
                }
            } else {
                apkDownloadTask = new ApkDownloadTask();
                apkDownloadTask.execute(new String[]{url, path});
            }
            //apk下载取消
        } else if (call.method.equals("cancelDownload")) {
            if (apkDownloadTask != null) {
                apkDownloadTask.cancel(true);
                apkDownloadTask = null;
            }
            MethodResultWrapper wrapper = peekWraper();
            if (wrapper != null) {
                wrapper.success("downloadApkCanceled");
            }

        } else if (call.method.equals("installApk")) {
            Object parameter = call.arguments();
            String path = "";
            if (parameter instanceof Map) {
                path = (String) ((Map) parameter).get("path");
            }
            if (TextUtils.isEmpty(path)) {
                MethodResultWrapper wrapper = peekWraper();
                if (wrapper != null) {
                    wrapper.success("FilePathFormatError");
                }
            } else {
                installApk(path);
            }
            //校验是否同一包名
        } else if (call.method.equals("checkSamePackage")) {
            Object parameter = call.arguments();
            String path = "";
            if (parameter instanceof Map) {
                path = (String) ((Map) parameter).get("path");
            }
            MethodResultWrapper wrapper = peekWraper();
            if (!isSamePackage(path)) {
                if (wrapper != null) {
                    wrapper.success("notSamePackage");
                }
            } else {
                if (wrapper != null) {
                    wrapper.success("SamePackage");
                }
            }
        } else {
            MethodResultWrapper wrapper = peekWraper();
            if (wrapper != null) {
                wrapper.notImplemented();
            }
        }
    }

    //安装apk
    private void installApk(String path) {
        Intent intent = new Intent(Intent.ACTION_VIEW);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", new File(path));
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        MethodResultWrapper wrapper = peekWraper();
        if (wrapper != null) {
            wrapper.success("installApkSuccess");
        }
        if (context != null) {
            context.startActivity(intent);
        }
    }

    //非同一包名的应用
    private void notSamePackage() {
        MethodResultWrapper wrapper = peekWraper();
        if (wrapper != null) {
            wrapper.success("notSamePackage");
        }
    }

    //非APK
    private void notApk() {
        MethodResultWrapper wrapper = peekWraper();
        if (wrapper != null) {
            wrapper.success("notApk");
        }
    }

    //下载Apk失败
    private void downloadApkFailed() {
        MethodResultWrapper wrapper = peekWraper();
        if (wrapper != null) {
            wrapper.success("downloadApkFailed");
        }
    }

    //是否apk
    private boolean isApkFile(String remoteApkPath) {
        boolean isApk = true;
        PackageManager pm = context.getPackageManager();
        PackageInfo pkgInfo = pm.getPackageArchiveInfo(remoteApkPath, PackageManager.GET_ACTIVITIES);
        if (pkgInfo == null) {
            isApk = false;
        }
        return isApk;
    }

    /**
     * 检测是否同包名
     *
     * @param remoteApkPath apk包的绝对路径
     */
    private boolean isSamePackage(String remoteApkPath) {
        boolean samePackage = true;
        if (context == null) {
            return samePackage;
        }
        String curPackageName = context.getPackageName();
        PackageManager pm = context.getPackageManager();
        PackageInfo pkgInfo = pm.getPackageArchiveInfo(remoteApkPath, PackageManager.GET_ACTIVITIES);
        if (pkgInfo != null) {
            ApplicationInfo appInfo = pkgInfo.applicationInfo;
            String packageName = appInfo.packageName; // 得到包名
            if (packageName != null && curPackageName != null) {
                //非同包名apk
                if (!packageName.equals(curPackageName)) {
                    samePackage = false;
                }
            }
        }
        return samePackage;
    }

    private class ApkDownloadTask extends AsyncTask<String, Float, Boolean> {
        boolean isInteriorSdCardPrivate = false;
        File file;
        String fileName;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            if (!Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) {
                isInteriorSdCardPrivate = true;
            }
        }

        @Override
        protected Boolean doInBackground(String... params) {
            fileName = params[1];
            file = new File(fileName);
            try {
                URL url = new URL(params[0]);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                InputStream in = connection.getInputStream();
                int count = 0;
                int len;
                byte[] b = new byte[1024];
                FileOutputStream out;
                if (isInteriorSdCardPrivate) {
                    out = context.openFileOutput(fileName, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
                } else {
                    out = new FileOutputStream(file);
                }
                while ((len = in.read(b)) != -1) {
                    out.write(b, 0, len);
                    count += len;
                    publishProgress(1.0f * count / connection.getContentLength());
                }
                out.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            if (file.exists() && file.isFile()) {
                return true;
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            String path = file.getAbsolutePath();
            if (aBoolean) {
                if (!isApkFile(path)) {
                    notApk();
                } else if (!isSamePackage(path)) {
                    //非同一APP
                    notSamePackage();
                } else {
                    installApk(path);
                }
            } else {
                downloadApkFailed();
            }
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            MethodResultWrapper wrapper = peekWraper();
            if (wrapper != null) {
                wrapper.success("downloadApkCanceled");
            }
        }

        @Override
        protected void onCancelled(Boolean aBoolean) {
            super.onCancelled(aBoolean);
            MethodResultWrapper wrapper = peekWraper();
            if (wrapper != null) {
                wrapper.success("downloadApkCanceled");
            }
        }

        @Override
        protected void onProgressUpdate(Float... values) {
            //把百分比传到Flutter
            channel.invokeMethod("updateProgress", values[0]);
        }

    }

}
